package it.uni.bo.monitoring.protocol.unmarshaller.analysis;

import it.uni.bo.monitoring.mapping.hibernate.Application;
import it.uni.bo.monitoring.mapping.hibernate.Client;
import it.uni.bo.monitoring.mapping.hibernate.Event;
import it.uni.bo.monitoring.mapping.hibernate.Ws;
import it.uni.bo.monitoring.mapping.hibernate.WsOperation;
import it.uni.bo.monitoring.protocol.server.DataObject;
import it.uni.bo.monitoring.protocol.unmarshaller.EventInfo;

import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;


import static it.uni.bo.monitoring.service.StaticFields.FAILB;
import static it.uni.bo.monitoring.service.StaticFields.INB;
import static it.uni.bo.monitoring.service.StaticFields.OUTB;
import static it.uni.bo.monitoring.service.StaticFields.QUERY_APPLICATION;
import static it.uni.bo.monitoring.service.StaticFields.QUERY_CLIENT;
import static it.uni.bo.monitoring.service.StaticFields.QUERY_EVENT;
import static it.uni.bo.monitoring.service.StaticFields.QUERY_EVENT_INBOUND;
import static it.uni.bo.monitoring.service.StaticFields.QUERY_OPERATION;
import static it.uni.bo.monitoring.service.StaticFields.QUERY_SEQUENCE_EVENT;
import static it.uni.bo.monitoring.service.StaticFields.QUERY_TIME_EVENT;
import static it.uni.bo.monitoring.service.StaticFields.QUERY_WS;


public class SemanticControl implements Validation {
	
	private Session session;
	private SessionFactory factory;
	private Logger l;
	
	private static final String ERROR_DC_KEY="nessuna chiave Inbound associata";
	private static final String ERROR_DC_EVENT="non esiste un evento associato alla chiave Inbound";
	private static final String ERROR_DC="direzione non conosciuta";
	private static final String ERROR_EC="evento precedente analizzato";
	private static final String ERROR_TC_EVENT="non posso inserire un evento antecedente";
	private static final String ERROR_US_CREDENTIALS="non esiste un utente con le credenziali fornite";
	private static final String ERROR_AC="non esiste un'applicazione associata all'URL fornito";
	private static final String ERROR_WS="non esiste un Web Service associato al namespace ed all'applicazione fornito";
	private static final String ERROR_OP="non esiste un'operazione associata al nome e al Web Service fornito";
	private static final String ERROR_SC="evento con lo stesso numero di sequenza";
	
	public SemanticControl(SessionFactory factory){
		l = Logger.getLogger(this.getClass());
		this.factory=factory;
	}

	public boolean validate(EventInfo ei) {
		session = factory.openSession();
	
		boolean ok=true;
			ok=		directionControl(ei)															&&
					eventControl(ei)																&&
					timeControl(ei);

			if(ei.getDataObject().getDirection()==INB){
				ok=	ok 																				&&
					userControl(ei)																	&&
					applicationControl(ei)															&&
					wsControl(ei)																	&&
					operationControl(ei)															&&
					sequenceControl(ei);
			}																			
					
		if(session!=null){
			if (session.isOpen()) 
				session.close(); }
		
		//l.info("SemanticControl: "+ok);
		return ok;
	}
	
	
	private boolean directionControl(EventInfo ei){
		DataObject rdo=ei.getDataObject();
		if(rdo.getDirection()!=INB){
			if(rdo.getDirection()==FAILB || rdo.getDirection()==OUTB){
				byte[] keyInbound = rdo.getKeyInbound();
                if(keyInbound==null){
                        l.error(ERROR_DC_KEY);
                        return false;
                }
                Query query = session.createQuery(QUERY_EVENT_INBOUND);
                query.setBinary(0,keyInbound);
                query.setMaxResults(1);
               // l.info("Hibernate: "+QUERY_EVENT_INBOUND+" [ "+keyInbound+" ]");
                Event e = (Event) query.uniqueResult();
                
                if(e==null){
                        l.error(ERROR_DC_EVENT);
                        return false;
                }
					ei.setApplication(e.getApplication());
					ei.setClient(e.getClient());
					ei.setWs(e.getWs());
					ei.setWsOperation(e.getWsOperation());
					//l.info("SemanticControl--directionControl ok");
					if(rdo.getDirection()==FAILB)
						ei.setFailDesc(new String(rdo.getFailDesc()));
			}
			else{
				l.error(ERROR_DC);
				return false;
			}
		}
        return true;
}
	
    /* controllo se ho precedentemente inserito lo stesso evento */
    private boolean eventControl(EventInfo ei) {
            Query query = session.createQuery(QUERY_EVENT);
            query.setBinary(0, ei.getIdE());
            query.setMaxResults(1);
            l.info("Hibernate: "+QUERY_EVENT+" [ "+ei.getIdE()+" ]");
            long num = (Long) query.uniqueResult();
            if(num==0){
                    //l.info("SemanticControl--eventControl ok");       
                    return true;
            }
            l.error(ERROR_EC);
            return false;
    }
    
    private boolean timeControl(EventInfo ei) {
            Query query = session.createQuery(QUERY_TIME_EVENT);
            query.setLong(0, ei.getTimestamp());
            query.setCharacter(1, ei.getDirection());
            query.setString(2, ei.getSession());
            query.setMaxResults(1);
            l.info("Hibernate: "+QUERY_TIME_EVENT+" [ "+ei.getTimestamp()+" "+ei.getDirection()+" "+ei.getSession()+" ]");
            long num = (Long) query.uniqueResult();
            if(num==0){
                    //l.info("SemanticControl--timeControl ok");        
                    return true;
            }
            l.error(ERROR_TC_EVENT+" ("+ei.getTimestamp()+")");
            return false;
    }
	
	private boolean userControl(EventInfo ei) {
			Query query = session.createQuery(QUERY_CLIENT);
			query.setString(0, ei.getUsername());
			query.setString(1, ei.getPassword());
			query.setMaxResults(1);
			//l.info("Hibernate: "+QUERY_CLIENT+" [ "+ei.getUsername()+" "+ ei.getPassword() +" ]");
			Object ob = query.uniqueResult();

			if(ob!=null){
				if(ob instanceof Client){
					ei.setClient((Client)ob);
					//l.info("SemanticControl-userControl ok");	
					return true;
				}
			}
			l.error(ERROR_US_CREDENTIALS+" ("+ei.getUsername()+")");
			return false;
	}
	
	private boolean applicationControl(EventInfo ei) {
			Query query = session.createQuery(QUERY_APPLICATION);
			query.setString(0, ei.getAppUrl());
			query.setMaxResults(1);
			//l.info("Hibernate: "+QUERY_APPLICATION+" [ "+ei.getAppUrl()+" ]");
			Object ob = query.uniqueResult();

			if(ob!=null){
				if(ob instanceof Application){
					ei.setApplication((Application)ob);
					//l.info("SemanticControl--applicationControl ok");	
					return true;
				}
			}
			l.error(ERROR_AC+" ("+ei.getAppUrl()+")");
			return false;
	}
	
	private boolean wsControl(EventInfo ei) {
			if(ei.getIdA()<0)
				return false;
			Query query = session.createQuery(QUERY_WS);
			query.setString(0, ei.getNamespace());
			query.setLong(1, ei.getIdA());
			query.setMaxResults(1);
			//l.info("Hibernate: "+QUERY_WS+" [ "+ei.getNamespace()+" "+ei.getIdA()+" ]");
			Object ob = query.uniqueResult();

			if(ob!=null){
				if(ob instanceof Ws){
					ei.setWs((Ws)ob);
					//l.info("SemanticControl--wsControl ok");	
					return true;
				}
			}
			l.error(ERROR_WS+" ("+ei.getNamespace()+", "+ei.getIdA()+")");
			return false;
	}
	
	private boolean operationControl(EventInfo ei) {
			if(ei.getIdWs()<0)
				return false;
			Query query = session.createQuery(QUERY_OPERATION);
			query.setLong(0, ei.getIdWs());
			query.setString(1, ei.getOperationName());
			query.setMaxResults(1);
			//l.info("Hibernate: "+QUERY_OPERATION+" [ "+ei.getIdWs()+" "+ei.getOperationName()+" ]");
			Object ob = query.uniqueResult();

			if(ob!=null){
				if(ob instanceof WsOperation){
					ei.setWsOperation((WsOperation)ob);
//					l.info("SemanticControl--operationControl ok");	
					return true;
				}
			}
			l.error(ERROR_OP+" ("+ei.getOperationName()+", "+ei.getIdWs()+")");
			return false;
	}
	
	private boolean sequenceControl(EventInfo ei) {
		Query query = session.createQuery(QUERY_SEQUENCE_EVENT);
		query.setLong(0,ei.getSeqNumber());
		query.setCharacter(1, ei.getDirection());
		query.setLong(2,ei.getIdA());
		query.setLong(3,ei.getIdU());
		query.setLong(4,ei.getIdWso());
		query.setLong(5,ei.getIdWs());
		query.setString(6,ei.getSession());
		query.setMaxResults(1);
		l.info("Hibernate: "+QUERY_SEQUENCE_EVENT+" [ "+ei.getSeqNumber()+" "+ei.getDirection()+" "+ei.getIdA()+" "+ei.getIdU()+" "+ei.getIdWso()+" "+ei.getIdWs()+" "+ei.getSession()+" ]");
		long num = (Long) query.uniqueResult();
		//TODO:da sistemare bug
		num=0;
		if(num==0){
			//l.info("SemanticControl--sequenceControl ok");        
			return true;
		}
		l.error(ERROR_SC+" ("+ei.getSeqNumber()+")");
		return false;
	}
}
